package models

import (
	"fmt"
	"math/rand"
	"net"
	"os"
	"os/signal"
	"runtime/debug"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

var m_二次登录 map[int32]string
var (
	Ver = "V20180609"
)
var 接收客户端 bool

/*启动服务器*/
func StartServer() {
	fmt.Printf("启动服务器,版本号:%s\r\n", Ver)
	接收客户端 = true
	游戏初始化()
	m_二次登录 = make(map[int32]string)
	listen, err := net.Listen("tcp", ":"+strconv.Itoa(Config.Server.Port+1))
	if err != nil {
		panic(err)
	}
	defer func() {
		fmt.Printf("存储系统信息... ...")
		SetConfig("系统", "时间", strconv.FormatUint(m_游戏时间, 10))
	}()
	go func() { //截获用户按CTRL+C指令
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt, os.Kill)

		<-c
		m_RunTime.Range(func(key, value interface{}) bool {
			value.(*RunTime).tcp.Close()
			return true
		})
		fmt.Printf("所有用户已退出...\r\n")
		listen.Close()
	}()
	go 客户端验证()
	//程序更新...........................
	go 系统_程序更新服务()
	go 系统_滚动消息服务()
	go 系统_游戏电信服务()
	go 系统_保管箱服务()
	go 系统时间服务()
	//启动网页服务
	go func() {
		router := gin.Default()
		router.Static("/web", "web")
		router.Static("/kxserver.exe", "/kxserver.exe")
		router.Run(Config.Web.Host + ":" + Config.Web.Port)
	}()
	fmt.Println(GetTime() + "开始接收客户端信息...")
	for {
		tcpConn, err := listen.Accept()
		if err != nil {
			fmt.Printf("用户接收程序退出\r\n")
			return
		}
		if 接收客户端 == true {
			rt := &RunTime{tcp: tcpConn}
			go func() {
				rt.exit = make(chan string, 10)
				rt.在线检测 = make(chan bool, 2)
				go OnUserConnect(rt)
				exit := false
				退出消息 := ""
				for {
					if exit == true {
						break
					}
					超时检测 := time.NewTimer(time.Second * 20) //20秒检测时间
					select {
					case t := <-rt.exit:
						退出消息 = t
						exit = true
					case <-rt.在线检测:
					case <-超时检测.C:
						退出消息 = "全局超时"
						exit = true
					}
					超时检测.Stop()
				}
				rt.tcp.Close()
				if rt.V角色 != nil { //如果角色还没有登录
					rt.Fun角色退出()
					fmt.Println(GetTime() + "保存角色:" + rt.V角色.V名字 + ",退出消息:" + 退出消息)
				} else {
					fmt.Println(GetTime() + "没有登录，不保存,退出消息:" + 退出消息)
				}
			}()
		} else {
			tcpConn.Close()
		}
	}
}

//功能 一个用户连接上TCP
func OnUserConnect(rt *RunTime) {
	defer func() {
		rt.exit <- "角色退出"
		debug.PrintStack()
		if err := recover(); err != nil {
			fmt.Println("错误信息:", err)
		}
		rt.tcp.Close()
	}()
	rt.txchan = make(chan []byte, 10)
	rt.rxchan = make(chan *Buff, 10)
	go rt.发送线程()
	//先发送验证数据
	head := (String2Byte("310631B5316D315B314231D33170319031D43189313931A231AA314A315731A5316031FB31BD31AF3188318A3126313B31253177317C318531DA316031C631AD31D031F531AE31F0310531173120311331B531D731DD3109313331583030316B31BB317F31F331143120314631B4312D31E331D2318831F1315231BE31F131AD315F31D231F7310C3183311931E4314931BC311831EA31053120318B3129311D31663143313B3114312931E8317631F1315231D4315331F431AD31DF318731E0319131F2310431903116318931FF3196312A314931BB319831C731103126319B310731C8310B31A83165314C31D931DD31CC31903185314F31A6313931A1312E"))
	rt.txchan <- head

	var rx *Buff
	rt.tcp.SetReadDeadline(time.Now().Add(time.Second * 30))
	{
		trx := make([]byte, 4096)
		if _, err := rt.tcp.Read(trx); err != nil {
			panic(err)
		}
	}
	go rt.接收线程() //到了这里才启动接收线程

	//接收客户端的回复 365字节
	select {
	case <-rt.rxchan: //接收数据
	case <-time.After(30 * time.Second): //超时10秒
		fmt.Printf("客户端第一笔同步时间失败...\r\n")
		return
	}
	/*
		//接收第二笔客户端发过来的数据
		//01 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 14
		rt.tcp.SetReadDeadline(time.Now().Add(time.Second * 30))
		if _, err := rt.tcp.Read(trx); err != nil {
			return
		}
	}*/
	//服务端发送字符串 22
	rt.AddHeadSend10(0x03, [][]byte{String2Byte("01000100")})

	//接收客户端的回复 365字节
	select {
	case rx = <-rt.rxchan: //接收数据
	case <-time.After(10 * time.Second): //超时10秒
		fmt.Printf("接收超时了...\r\n")
		return
	}

	//在这里有两种，一种是密码串，一种是用户重新登录
	var 密码串 string
	if len(rx.Buff) == 30 { //重复登录
		rx.GetBytes(20)
		rx.GetInt32()
		rx.GetInt16()
		原来ID := rx.GetInt32()
		密码串 = m_二次登录[原来ID]
		if len(密码串) == 0 {
			panic("错误的密码串")
		}
		delete(m_二次登录, 原来ID)
	} else {
		rx.GetBytes(592 / 2)
		密码串 = rx.GetStringAndLen()
	}
	{
		//开始发送 服务器的名称 Sephiroth测试
		//rt.AddHeadSend10(0x0A, [][]byte{{}, String2Byte("E10000000000000E0000005365706869726F7468B2E2CAD4000100000000")})
		tx := CreateBuff(30)
		tx.AddInt16(0x00E1)
		tx.AddByte(0)
		tx.AddInt32(0)
		tx.AddStringAndLen("凯旋归来")
		tx.AddStringAndLen("")
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
	}
	用户 := rt.获取角色列表(密码串)
	lastlen := 65535
	登陆 := false
	for 登陆 == false {
		if len(rx.Buff) == lastlen {
			panic(fmt.Sprintf("未处理指令[%04d]:%s\r\n", len(rx.Buff), Byte2String(rx.Buff)))
		}
		rt.在线检测 <- true
		select {
		case rx = <-rt.rxchan:
			break
		case <-time.After(time.Second * 2): //这样可以保证在用户登录时，如果不登录，那么将不会退出，
			continue
		}
		if len(rx.Buff) < 18 { //有人通知退出了
			return
		}
		lastlen = len(rx.Buff)
		var xor byte
		for _, v := range rx.Buff[:18] {
			xor ^= v
		}
		if xor != 0 {
			panic(fmt.Sprintf("非法数据[%04d]:%s\r\n", len(rx.Buff), Byte2String(rx.Buff)))
		}

		switch rx.Buff[0] {
		case 0x09:
			var cmd int
			cmd = (int(rx.Buff[19]) << 8) | int(rx.Buff[18])
			switch cmd {
			case 0x008D:
				rx.GetBytes(20)
				rx.GetInt32()
				角色名称 := rx.GetStringAndLen()
				fmt.Println(GetTime() + "角色登录:" + 角色名称)
				rt.Func角色登录(用户, 角色名称)
				fmt.Println(GetTime() + "登录完成:" + 角色名称)
				登陆 = true
				break
			case 0x008C: //删除用户
				rx.GetBytes(18)
				rx.GetBytes(6)              //未知
				用户名 := rx.GetStringAndLen() //获取删除角色名称
				rt.角色_删除角色(用户, 用户名)
				tx := CreateBuff(7)
				tx.AddInt16(0xE3)
				tx.AddInt32(0x00)
				tx.AddByte(0x00)
				rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
			case 0x008B: //创建一个角色 114
				角色 := &S角色列表{}
				rx.GetBytes(24) //删除5个0
				角色.V名字 = rx.GetStringAndLen()
				//在这里检测名称
				if strings.Index(角色.V名字, "'") != -1 {
					rt.操作失败(0x0E01)
					break
				}
				角色.V种族 = rx.GetStringAndLen()
				角色.V性别 = rx.GetBool()
				角色.V发型发色 = rx.GetStringAndLen()
				rx.GetStringAndLen()           //FaceHM1
				rx.GetStringAndLen()           //HunterSuit
				角色.V职业 = rx.GetStringAndLen()  //OneHand
				角色.V所属地 = rx.GetStringAndLen() //Ladianes
				角色.PlayId = 用户.Id              //设置属于哪个用户
				rt.V角色 = 角色
				if rt.Fun创建角色() == false {
					rt.操作失败(0x0E01)
				} else {
					rt.Fun角色退出()
					rt.Complete()
				}
			case 0x01A9: //用户登录时，处于等待时间
				rx.GetBytes(20)
			default:
				fmt.Printf(GetTime()+"未知[%04d]:%s\r\n", len(rx.Buff), Byte2String(rx.Buff))
			}

		}
	}
	//在这里要求所有的接收数据必须处理完成，否则程序出错
	lastlen = 65535
	每秒检测 := time.Now().Add(time.Second)
	var lastx, lasty int32
	m := rt.V角色内容
	死亡通知 := false
	for {
		rt.在线检测 <- true

		if len(rx.Buff) == lastlen {
			panic(GetTime() + fmt.Sprintf("未处理指令[%04d]:%s\r\n", len(rx.Buff), Byte2String(rx.Buff)))
		}
		if m.V基础属性[E基础属性_当前血量] <= 0 {
			if 死亡通知 == false {
				m.V是否死亡 = true
				死亡通知 = true
				if m.V最后攻击者 != nil {
					var 名称 string
					switch m.V最后攻击者.V类别 {
					case E类别_人物:
						名称 = m.V最后攻击者.V内容.(*S角色列表).V名字
					case E类别_怪物:
						名称 = m.V最后攻击者.V内容.(*Struct怪物列表).V怪物中文名
					default:
						名称 = "某某某"
					}
					rt.消息_系统消息(3, "您已被:"+名称+"杀死!")
				}

				if m.V基础属性[E基础属性_当前血量] <= 0 {
					rt.动作_自己死亡()
					for _, v := range m.V额外属性 {
						v.V到期时间 = time.Now()
					}
					动作_怪物死亡(m)
					//m.X, m.Y = F位置_游戏位置转UE4位置(rt.V角色.V出生x, rt.V角色.V出生y)
				}
			}
		} else {
			死亡通知 = false
		}
		select {
		case rx = <-rt.rxchan:
			break
		case 交换数据 := <-m.VChan:
			switch 交换数据.V类型 {
			case E交换数据类型_增加经验:
				if m.V是否死亡 == true {
					break
				}
				增加经验 := 交换数据.V内容.(float32)
				if m.V区域 != nil {
					增加经验 *= m.V区域.V经验倍数
				}
				rt.V角色.V当前经验 += int64(增加经验)
				i := 0
				for ; i < 1000; i++ { //限制1000次内一定会出去
					if 总经验, ok := m_等级经验[rt.V角色.V等级]; ok == true {
						if rt.V角色.V当前经验 >= 总经验 {
							rt.V角色.V当前经验 -= 总经验
							rt.角色升级()
							continue
						}
					}
					break
				}
				if i >= 1000 {
					fmt.Println("循环超过次数:位置1")
				}
				rt.发送用户信息(用户信息_经验值)
			case E交换数据类型_攻击效果:
				效果 := 交换数据.V内容.(S交换攻击效果)
				//rt.消息_系统消息(3, fmt.Sprintf("效果:%d,掉血%d,掉蓝:%d", int(效果.V效果), int(效果.V掉血), int(效果.V掉蓝)))
				效果.V掉血 *= -1
				switch 效果.V效果 { // 0掉血 1防御 2眩晕 3暴击
				case 0:
					rt.动作_怪物掉血(交换数据.V发送人.Id, int32(效果.V掉血))
				case 1:
					rt.动作_怪物闪避(交换数据.V发送人.Id)
				case 2:
					rt.动作_怪物眩晕(交换数据.V发送人.Id, int32(效果.V掉血))
				case 3:
					rt.动作_怪物致命(交换数据.V发送人.Id, int32(效果.V掉血))
				default:
					panic("未知")
				}
			case E交换数据类型_透传数据: //有角色移动 只有在场景里的才会移动，否则客户端会弹错
				找到 := false
				if 交换数据.V发送人 == nil { //系统 发送
					找到 = true
				} else {
					for k, _ := range m.V场景 {
						if k == 交换数据.V发送人.Id {
							找到 = true
							break
						}
					}
				}
				if 找到 == true {
					交换 := 交换数据.V内容.(S交换角色通讯)
					rt.AddHeadSend10(交换.VCMD, [][]byte{交换.V信息[:交换.VHeadlen], 交换.V信息[交换.VHeadlen:]})
				}
			case E交换数据类型_查看摊位物品: //有人要查看物品
				if m.V是否死亡 == true {
					break
				}
				查询信息 := 交换数据.V内容.(S查询摊位物品信息)
				if rt.V角色.V状态 != E角色状态_摆摊 {
					查询信息.V物品 <- nil
					break
				}
				摆摊 := rt.V角色.V状态内容.(*S摆摊列表)
				var 物品 *Struct物品列表
				for _, v := range 摆摊.V物品列表 {
					if v.V摊位X == 查询信息.V位置X && v.V摊位Y == 查询信息.V位置Y {
						物品 = v.V物品
						break
					}
				}
				查询信息.V物品 <- 物品
				break
			case E交换数据类型_购买摊位物品: //有人要购买物品
				if m.V是否死亡 == true {
					break
				}
				购买信息 := 交换数据.V内容.(S交换购买信息)
				if rt.V角色.V状态 != E角色状态_摆摊 {
					购买信息.V购买的物品 <- nil
					break
				}
				var 摆摊物品 *S摆摊物品
				摆摊 := rt.V角色.V状态内容.(*S摆摊列表)
				for _, v := range 摆摊.V物品列表 {
					if (v.V摊位X == 购买信息.V位置X) && (v.V摊位Y == 购买信息.V位置Y) {
						摆摊物品 = v
						break
					}
				}
				if 摆摊物品 == nil {
					购买信息.V购买的物品 <- nil
					break
				}
				物品信息 := 物品_获取物品信息(摆摊物品.V物品.V信息ID)
				//算下金额是否合适
				if 物品信息.V数量 == true {
					if 摆摊物品.V售价*int64(购买信息.V数量) != 购买信息.V购买金额 {
						购买信息.V购买的物品 <- nil
						break
					}

				} else {
					if 摆摊物品.V售价 != 购买信息.V购买金额 {
						购买信息.V购买的物品 <- nil
						break
					}
				}
				背包 := rt.背包_获取背包(摆摊物品.V背包ID)
				购买的物品, err := rt.背包_取出指定位置物品(背包, 摆摊物品.V背包X, 摆摊物品.V背包Y, 购买信息.V数量)
				if err != nil {
					购买信息.V购买的物品 <- nil
					break
				}
				if 物品信息.V数量 == true {
					if 购买的物品.V数量 != 购买信息.V数量 {
						panic("购买的数量不对应")
					}
				}
				rt.V角色.V金币 += 购买信息.V购买金额
				摆摊.V出售金额 += 购买信息.V购买金额
				购买信息.V购买的物品 <- 购买的物品 //把物品发送给对方吧

				摆摊物品.V物品 = rt.背包_查询位置物品(背包, 摆摊物品.V背包X, 摆摊物品.V背包Y) //更新 不删除
				if 物品信息.V数量 == false {
					if 摆摊物品.V物品 != nil {
						panic("不带数量的物品，在卖出去的情况下，不可能还存在")
					}
				}
				rt.同步_背包指定点(背包, 摆摊物品.V背包X, 摆摊物品.V背包Y, true)
				rt.发送用户信息(用户信息_金币)
				rt.摆摊_设置总出售金币(摆摊.V出售金额)

				//通知所有人，某位置物品的数量变了
				/* //$for _, 查看摊位人 := range rt.V角色.V摆摊.V查看角色列表 {
					var ort *RunTime
					if t, ok := m_RunTime.Load(查看摊位人.V内容.(*S角色列表).Id); ok == true {
						ort = t.(*RunTime)
					}
					if ort == nil {
						continue
					}
					ort.动作_摆摊取回物品(摆摊物品.V背包ID, 摆摊物品.V背包X, 摆摊物品.V背包Y, 摆摊物品.V摊位X, 摆摊物品.V摊位Y)
					if 摆摊物品.V物品 != nil {
						ort.动作_摆摊放置物品(摆摊物品.V背包ID, 摆摊物品.V背包X, 摆摊物品.V背包Y, 摆摊物品.V摊位X, 摆摊物品.V摊位Y, 摆摊物品.V售价, 摆摊物品.V物品)
					}
				}
				*/
				//通知自己
				rt.动作_摆摊取回物品(摆摊物品.V背包ID, 摆摊物品.V背包X, 摆摊物品.V背包Y, 摆摊物品.V摊位X, 摆摊物品.V摊位Y)
				if 摆摊物品.V物品 != nil {
					rt.动作_摆摊放置物品(摆摊物品.V背包ID, 摆摊物品.V背包X, 摆摊物品.V背包Y, 摆摊物品.V摊位X, 摆摊物品.V摊位Y, 摆摊物品.V售价, 摆摊物品.V物品)
				}
				/*CMD 0A,,84 00 0A 00 00 00 47 61 75 67 65 43 6F 69 6E 00 00 00 00 00
				CMD 0A,,47 01 01 00 00 00 00 00 00 00 00 00 00 00
				*/
			case E交换数据类型_查看摊位: //有人查看摆摊
				if m.V是否死亡 == true {
					break
				}
				var ort *RunTime
				if t, ok := m_RunTime.Load(交换数据.V发送人.V内容.(S角色列表).V名字); ok == true {
					ort = t.(*RunTime)
				}
				if ort == nil {
					break
				}
				if rt.V角色.V状态 != E角色状态_摆摊 {
					ort.消息_系统消息(3, "对方已取消摆摊状态")
					break
				}
				摆摊 := rt.V角色.V状态内容.(*S摆摊列表)
				摆摊.V查看角色列表 = append(摆摊.V查看角色列表, 交换数据.V发送人.Id)
				tx := CreateBuff(24)
				tx.AddInt16(0x01A0)
				tx.AddInt32(m.Id)
				ort.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
				for _, v := range 摆摊.V物品列表 {
					if v.V物品 == nil {
						continue
					}
					ort.动作_摆摊放置物品(v.V背包ID, v.V背包X, v.V背包Y, v.V摊位X, v.V摊位Y, v.V售价, v.V物品)
				}
			case E交换数据类型_取消查看摊位: //有人取消查看
				var ort *RunTime
				if t, ok := m_RunTime.Load(交换数据.V发送人.V内容.(S角色列表).V名字); ok == true {
					ort = t.(*RunTime)
				}
				if ort == nil {
					break
				}
				if rt.V角色.V状态 != E角色状态_摆摊 {
					ort.消息_系统消息(3, "对方已取消摆摊状态")
					break
				}
				摆摊 := rt.V角色.V状态内容.(*S摆摊列表)
				for i := 0; i < len(摆摊.V查看角色列表); i++ {
					if 摆摊.V查看角色列表[i] == 交换数据.V发送人.Id {
						摆摊.V查看角色列表[i] = -1
						break
					}
				}
			case E交换数据类型_怪物死亡:
				//开始生成掉落物品,物品来源分三部分
				//第一部分： 全服掉落物品
				//第二部分： 等级掉落物品
				//第三部分： 区域掉落物品
				//这三部分合m 成一个列表
				if 掉落物品S, ok := m_怪物掉宝[交换数据.V内容.(string)]; ok == true {
					全体物品获得率 := int(m.V基础属性[E基础属性_全体物品获得率])
					if 全体物品获得率 <= 0 {
						全体物品获得率 = 1
					}
					//魔法物品获得率:=m.V基础属性[E基础属性_魔法物品获得率]
					掉落数量 := 0
					最多掉落 := 全体物品获得率 / 10 //最少循环10次
					循环上限 := 全体物品获得率 + 10
					循环次数 := 0
					for 物品中文名, 掉宝机率 := range 掉落物品S.V掉落物品 {
						循环次数++
						if 循环次数 > 循环上限 {
							break
						}
						掉宝机率 = int(float32(掉宝机率) / m_历史长河.V掉宝倍率) //整个服务器调整掉宝倍率
						if 掉宝机率 <= 0 {                           //不能为0
							掉宝机率 = 1
						}
						掉宝机率 = rand.Intn(掉宝机率)
						if 掉宝机率 <= 10 {
							复制物品, err := 物品_获取系统物品列表_中文(物品中文名)
							if err != nil {
								continue
							}
							物品ID := 复制物品.Id
							掉落物品 := 创建物品(物品ID)
							if 掉落物品.V数量 != 0 {
								掉落物品.V数量 = uint16(rand.Intn(int(掉落物品.V数量)))
								if 掉落物品.V数量 == 0 {
									掉落物品.V数量 = 1
								}
							}
							m.V空间.F添加内容(E类别_物品, 交换数据.V发送人.X, 交换数据.V发送人.Y, 0, 0, 掉落物品)
							掉落数量++
							if 掉落数量 >= 最多掉落 {
								break
							}
						}
					}
				}
			default:
				rt.角色_处理信息变动(m.F处理接收数据(交换数据))
			}
			continue
		case <-time.After(每秒检测.Sub(time.Now())):
			每秒检测 = 每秒检测.Add(time.Second)
			rt.角色_处理信息变动(m.F检测())
			continue
		}
		lastlen = len(rx.Buff)
		var xor byte
		for _, v := range rx.Buff[:18] {
			xor ^= v
		}
		if xor != 0 {
			panic(fmt.Sprintf("非法数据[%04d]:%s\r\n", len(rx.Buff), Byte2String(rx.Buff)))
		}
		switch rx.Buff[0] {
		case 0x09:
			rt.Fun处理09指令(用户, rx)
		case 0x0C:
			tx := CreateBuff(36)
			rx.GetBytes(18) //去掉前18个
			累加数 := rx.GetInt16()
			//在这里进行判断用户的X,Y,Z是否正确
			newx := rx.GetInt32()
			newy := rx.GetInt32()
			if rx.GetInt32() != 0 {
				panic("x")
			}
			if rx.GetInt16() != 0x01 {
				panic("x")
			}
			位置Z := rx.GetInt32() //z
			未知1 := rx.GetInt32() //DE 92 13 00
			未知2 := rx.GetInt32() //0
			方向 := rx.GetInt32()  //4B 0E 00 00
			if rx.GetInt32() != 0 {
				panic("x")
			} //0
			rx.GetInt32() //跳的时候是0 不跳的时候是50 37 1A 10
			rx.GetInt32() //跳的时候是0 不跳的时候是FFFFFFFF

			未知7 := rx.GetInt32() //04 F9 18 00
			方向1 := rx.GetInt32() //方向
			未知8 := rx.GetInt32() //36 A1 0C 00
			未知9 := rx.GetInt32() //CC E7 FF FF
			类型 := rx.GetByte()
			switch 类型 {
			case 0:
				rx.GetFloat() // 54 B3 16 44
				if rx.GetFloat() != 0x01 {
					panic("x")
				}

			case 1:
				rx.GetInt32()
				rx.GetInt32()
				rx.GetInt32()
				rx.GetFloat() //00 00 16 44
			default:
				panic("x")
			}
			m.Z = 位置Z
			if newx != m.X || newy != m.Y || 类型 != 0 {
				if m.V内容.(*S角色列表).V名字 == "GM" {
					坐标x, 坐标y := F位置_UE4位置转游戏位置(m.X, m.Y)
					if 坐标x < 坐标.X0 {
						坐标.X0 = 坐标x
					}
					if 坐标y < 坐标.Y0 {
						坐标.Y0 = 坐标y
					}
					if 坐标x > 坐标.X1 {
						坐标.X1 = 坐标x
					}
					if 坐标y > 坐标.Y1 {
						坐标.Y1 = 坐标y
					}
				}
				if m.V空间.F计算两点距离(m.X, m.Y, newx, newy) < 10 { //如果两次间距离过长，很可能角色移动了，但客户端还没反应过来
					m.F内容移动(newx, newy) //通知地图 移动位置
					newx = m.X
					newy = m.Y
					//通知其它角色人物移动
					tx := CreateBuff(100)
					tx.AddInt32(m.Id) //添加自己的ID
					tx.AddInt32(m.X)
					tx.AddInt32(m.Y)
					tx.AddInt32(0)
					//开始添加后面的数据，需要原封不动
					tx.AddInt16(0x01)
					tx.AddInt32(位置Z)
					tx.AddInt32(未知1)
					tx.AddInt32(未知2)
					tx.AddInt32(方向)
					tx.AddInt32(0)
					if 类型 == 0 {
						tx.AddInt32(0x101A3750)
						tx.AddInt32(-1)
					} else {
						tx.AddInt32(0x00)
						tx.AddInt32(0x00)
					}
					tx.AddInt32(未知7)
					tx.AddInt32(方向1)
					tx.AddInt32(未知8)
					tx.AddInt32(未知9)
					tx.AddByte(类型)
					switch 类型 {
					case 0:
						tx.AddFloat(600)
						tx.AddFloat(0x01)
					case 1:
						tx.AddInt32(0x00)
						tx.AddInt32(0x00)
						tx.AddInt32(0x00)
						tx.AddFloat(600)
					}
					向周边发送消息(m, 0x0E, 16, tx.Buff)
				}
			}
			{
				tx.AddInt16(累加数) //累加数
				tx.AddInt32(m.X)
				tx.AddInt32(m.Y)
				tx.AddInt32(0)
				tx.AddInt32(0)
				rt.AddHeadSend10(0X0D, [][]byte{tx.Buff})
			}
			m.周边内容检测() //周边的内容检测
		default:
			fmt.Printf("未知C->S[%04d]:%s\r\n", len(rx.Buff), Byte2String(rx.Buff))
		}
		//只要角色移动位置了，就需要检测是否进入到了另一个地图中，然后切换操作
		if (lastx != m.X) || (lasty != m.Y) || (m.V区域 == nil) {
			lastx = m.X
			lasty = m.Y
			位置定义 := 位置_获取位置(F位置_UE4位置转游戏位置(lastx, lasty))
			if (位置定义 != nil) && (m.V区域 == nil || m.V区域.Id != 位置定义.Id) {
				if (位置定义.V等级下限 != 0 && rt.V角色.V等级 < 位置定义.V等级下限) || (位置定义.V等级上限 != 0 && rt.V角色.V等级 > 位置定义.V等级上限) {
					x, y := F位置_游戏位置转UE4位置(int32(位置定义.X0-10), int32(位置定义.Y0-10))
					rt.Func位置移动(x, y, 0)
					rt.消息_系统消息(3, fmt.Sprintf("您的等级无法在此区域内活动,此区域等级要求%d~%d", 位置定义.V等级下限, 位置定义.V等级上限))
				}
				m.V区域 = 位置定义
				if m.V区域.VPK == 0 { //在指定位置不能再PK了
					rt.V角色.VPK = false
					rt.动作_切换PK()
				} else if m.V区域.VPK == 2 {
					rt.V角色.VPK = true
					rt.动作_切换PK()
				}
				tx := CreateBuff(100)
				tx.AddInt16(0x0123)
				tx.AddInt32(0x01)
				tx.AddStringAndLen(位置定义.V音乐)
				tx.AddInt32(0x01)
				tx.AddStringAndLen(位置定义.V音乐)
				rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})

				tx = CreateBuff(100)
				tx.AddInt16(0x0122)
				区域名称 := 位置定义.V区域名称
				if m.V空间 != m_默认空间 {
					区域名称 = "[副]" + 区域名称
				}
				tx.AddStringAndLen(区域名称)
				tx.AddStringAndLen(区域名称)
				rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})

				rt.角色_处理信息变动(true, nil, nil, nil) //重新计算
			}
		}
	}
}
func (rt *RunTime) Fun处理09指令(用户 *Struct用户信息, rx *Buff) {
	m := rt.V角色内容
	if m == nil {
		panic("不可能位置")
	}
	var cmd int
	cmd = int(rx.Buff[19])
	cmd <<= 8
	cmd |= int(rx.Buff[18])
	switch cmd {
	case 0x000E: //用户退出
		panic("用户退出")
	case 0x000F: //人物拿起武器
		rx.GetBytes(20) //清除指令
		if m.V是否死亡 == true {
			break
		}
		rt.动作_人物拿起武器(true)
	case 0x0010: //人物背起武器
		rx.GetBytes(20) //清除指令
		if m.V是否死亡 == true {
			break
		}
		rt.动作_人物拿起武器(false)
	case 0x0012: //按下INSERT键
		rx.GetBytes(20) //清除指令
	case 0x0013:
		rx.GetBytes(20)
		if m.V是否死亡 == true {
			break
		}
		if m.V区域.VPK != 0 {
			rt.V角色.VPK = true
			rt.动作_切换PK()
		} else {
			rt.消息_系统消息(3, "此区域禁止PK")
		}
	case 0x0014:
		rx.GetBytes(20)
		if m.V是否死亡 == true {
			break
		}
		rt.V角色.VPK = false
		rt.动作_切换PK()

	case 0x0015: //呼喊 123456789
		rx.GetBytes(20)
		类型 := rx.GetByte()
		话语 := rx.GetStringAndLen()
		if m.V是否死亡 == true {
			break
		}
		switch 类型 {
		case 1: //说话 //呼喊
			m_电信服务 <- &电信{
				来源:   m,
				类型:   E说话,
				通讯内容: 话语,
			}
		case 2:
			m_电信服务 <- &电信{
				来源:   m,
				类型:   E呼喊,
				通讯内容: 话语,
			}
		default:
			panic("未知说话类型:" + strconv.Itoa(int(类型)))
		}
	case 0x0016: //用户加点
		rx.GetBytes(20)
		属性 := rx.GetByte()
		点数 := uint16(rx.GetInt32())
		if m.V是否死亡 == true {
			break
		}
		switch 属性 {
		case 0:
			rt.Func角色加点(点数, 0, 0, 0, 0, 0, 0, 0)
			rt.发送用户信息(用户信息_力量)
		case 1:
			rt.Func角色加点(0, 点数, 0, 0, 0, 0, 0, 0)
			rt.发送用户信息(用户信息_敏捷)
		case 2:
			rt.Func角色加点(0, 0, 点数, 0, 0, 0, 0, 0)
			rt.发送用户信息(用户信息_精神)
		case 3:
			rt.Func角色加点(0, 0, 0, 点数, 0, 0, 0, 0)
			rt.发送用户信息(用户信息_白魔法)
		case 4:
			rt.Func角色加点(0, 0, 0, 0, 点数, 0, 0, 0)
			rt.发送用户信息(用户信息_红魔法)
		case 5:
			rt.Func角色加点(0, 0, 0, 0, 0, 点数, 0, 0)
			rt.发送用户信息(用户信息_蓝魔法)
		case 6:
			rt.Func角色加点(0, 0, 0, 0, 0, 0, 点数, 0)
			rt.发送用户信息(用户信息_黄魔法)
		case 7:
			rt.Func角色加点(0, 0, 0, 0, 0, 0, 0, 点数)
			rt.发送用户信息(用户信息_黑魔法)
		default:
			panic("")
		}
		rt.发送用户信息(用户信息_可分配点数)
	case 0x0017: //角色死了，重新再来
		rx.GetBytes(22)
		if m.V是否死亡 == false {
			break
		}
		m.V是否死亡 = false
		x, y := F位置_UE4位置转游戏位置(m.X, m.Y)
		位置定义 := 位置_获取位置(x, y)
		if len(位置定义.V复活点) == 2 { //如果地图定义了复活点,则在指定复活点复活
			xx := 位置定义.V复活点[0]
			yy := 位置定义.V复活点[1]
			x, y := F位置_游戏位置转UE4位置(xx, yy)
			rt.Func位置移动(x, y, 0)
			m.V基础属性[E基础属性_当前血量] = m.V基础属性[E基础属性_总血量]
			m.V基础属性[E基础属性_当前蓝量] = m.V基础属性[E基础属性_总蓝量]
			rt.发送用户信息(用户信息_血量, 用户信息_蓝量)
		} else {
			x, y := F位置_游戏位置转UE4位置(rt.V角色.V出生x, rt.V角色.V出生y)
			rt.Func位置移动(x, y, 0)
			m.V基础属性[E基础属性_当前血量] = m.V基础属性[E基础属性_总血量]
			m.V基础属性[E基础属性_当前蓝量] = m.V基础属性[E基础属性_总蓝量]
			rt.发送用户信息(用户信息_血量, 用户信息_蓝量)
		}
	case 0x0018: //耳语
		rx.GetBytes(20) //去掉前面无用数据
		对谁说 := rx.GetStringAndLen()
		话语 := rx.GetStringAndLen()
		if m.V是否死亡 == true {
			break
		}
		rt.消息_底部框显示文字(5, "->"+对谁说+":"+话语)
		m_电信服务 <- &电信{
			来源:   m,
			目标名字: 对谁说,
			类型:   E耳语,
			通讯内容: 话语,
		}
	case 0x0019: //登记位置点
		rx.GetBytes(24) //去掉前面无用数据
		位置名称 := rx.GetStringAndLen()
		if m.V是否死亡 == true {
			break
		}
		x, y := F位置_UE4位置转游戏位置(m.X, m.Y)
		位置定义 := 位置_获取位置(x, y)
		if 位置定义.V位置登记 == false {
			rt.消息_系统消息(3, "此位置不能登记")
		} else {
			if err := rt.位置_位置登记(位置名称, x, y); err != nil {
				rt.消息_系统消息(3, err.Error())
			}
		}
	case 0x001B: //按R 打开位置窗口
		rx.GetBytes(24) //清除需要的数据
		if m.V是否死亡 == true {
			break
		}
		rt.位置登记_输出所有位置()
	case 0x001C: //移动 ，最后四位是移动的目标 	rt.Func处理位置移动(rx)
		rx.GetBytes(20)
		id := rx.GetInt32()

		if m.V是否死亡 == true {
			break
		}
		if rt.脚本_查询条件("移动卷轴", 1) != nil {
			rt.消息_系统消息(3, "没有移动卷轴!")
			break
		}
		rt.脚本_执行条件("移动卷轴", 1)
		address, ok := rt.V位置登记[id]
		if ok == false {
			panic("不存在的位置")
		}
		rt.执行脚本(fmt.Sprintf("/移动 %d %d %d", address.X, address.Y, address.Z), -1)
		//rt.Func位置移动()
		rt.消息_系统消息(3, fmt.Sprintf("移动到位置:[%d]", address.Id))
		//rt.Func公告("老子现在心情好，不收你费用")
	case 0x001D: //		rt.技能_处理设置物理技能(rx)
		rx.GetBytes(20)
		技能类型 := rx.GetByte()
		技能名称 := rx.GetStringAndLen()

		if m.V是否死亡 == true {
			break
		}
		rt.技能_设置技能_英文(技能类型, 技能名称)
		tx := CreateBuff(len(技能名称) + 11)
		tx.AddInt16(0x00C8)
		tx.AddByte(技能类型)
		tx.AddStringAndLen(技能名称)
		tx.AddInt32(0)
		tx.AddInt32(0)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})

		rt.角色_属性计算(false)
	case 0x001E:
		rx.GetBytes(20)
		位置ID := rx.GetInt32()
		位置, ok := rt.V位置登记[位置ID]
		if ok == false {
			panic("正在删除不存在的位置")
		}
		db.Where("id=?", 位置.Id).Delete(位置)
		delete(rt.V位置登记, 位置ID)
		rt.位置登记_输出所有位置()
		rt.消息_系统消息(3, "位置已删除!")
	case 0x001F: //在物品栏放置物品 这个物品栏里显示的不是一个物品的数量，显示的是全部的数量
		rx.GetBytes(20)
		rx.GetStringAndLen() //物理技能 :=
		rx.GetStringAndLen() //物理魔法技能 :=
		rx.GetStringAndLen() //魔法技能 :=
		for i := 0; i < 12; i++ {
			类型 := rx.GetByte()
			if 类型 != 0 {
				rt.V角色.V数字栏[i] = strconv.Itoa(int(类型)) + ":" + rx.GetStringAndLen()
			}
		}
		for i := 0; i < 12; i++ {
			if rx.GetByte() != 0x00 {
				rx.GetStringAndLen()
			}
		}
		for i := 0; i < 12; i++ {
			类型 := rx.GetByte()
			if 类型 != 0 {
				rt.V角色.V功能栏[i] = strconv.Itoa(int(类型)) + ":" + rx.GetStringAndLen()
			}
		}
	case 0x0022: //从地上捡起一件物品
		rx.GetBytes(20)
		物品ID := rx.GetInt32()

		if m.V是否死亡 == true {
			break
		}
		if _, ok := m.V场景[物品ID]; ok == false {
			rt.消息_系统消息(3, "位置过远!")
		}
		物品内容 := m.V空间.F删除内容(物品ID)
		if 物品内容 == nil { //已经被人捡起
			break
		}
		物品 := 物品内容.V内容.(*Struct物品列表)
		rt.地图_消失内容(物品ID)
		rt.背包_放置物品(物品)
	case 0x0023, 0x0025: //从背包中取出一件物品放到角色身上
		rx.GetBytes(20)
		var 背包ID, 背包X, 背包Y uint8
		var 位置 byte
		if cmd == 0x0023 {
			背包ID = uint8(rx.GetInt32())
			背包X = uint8(rx.GetInt32())
			背包Y = uint8(rx.GetInt32())
			位置 = rx.GetByte()
		} else {
			位置 = rx.GetByte()
			背包ID = uint8(rx.GetInt32())
			背包X = uint8(rx.GetInt32())
			背包Y = uint8(rx.GetInt32())
		}

		if m.V是否死亡 == true {
			break
		}
		背包 := rt.背包_获取背包(背包ID)
		物品, err := rt.背包_取出指定位置物品(背包, 背包X, 背包Y, 0)
		if err != nil {
			rt.消息_系统消息(3, err.Error())
			break
		}
		rt.V物品列表[物品.Id] = 物品 //还存在的物品
		装备上 := false
		defer func() {
			if 装备上 == false {
				if err := rt.背包_存放物品(背包, 背包X, 背包Y, 物品); err != nil {
					panic("刚才还能放得下，现在为什么放不下")
				}
			} else {
				rt.角色_属性计算(false)
			}
		}()
		if err := rt.装备_判断是否可装备(物品, 位置); err != nil {
			rt.消息_系统消息(3, fmt.Sprintf("%s,位置:%d", err.Error(), 位置))
			break
		}
		被替换物品 := rt.装备_获取指定位置物品(位置)
		var 新X, 新Y uint8
		if 被替换物品 != nil {
			if x, y, ok := rt.背包_查询空位(背包, 被替换物品); ok == false {
				rt.消息_系统消息(3, "没有空余位置")
				break
			} else {
				新X = x
				新Y = y
			}
			rt.装备_卸载指定位置物品(位置)
			rt.同步_角色装备(位置, false) //取下时不更新
		}
		rt.装备_穿着指定位置物品(物品, 位置)
		rt.同步_背包指定点(背包, 背包X, 背包Y, false)
		rt.同步_角色装备(位置, true)
		if 被替换物品 != nil {
			if err := rt.背包_存放物品(背包, 新X, 新Y, 被替换物品); err != nil {
				panic("刚才还能放得下，现在为什么放不下")
			}
			rt.同步_背包指定点(背包, 新X, 新Y, false)
		}
		装备上 = true
	case 0x0024: //取出身上的装备并放到背包中
		rx.GetBytes(20)
		位置 := rx.GetByte()
		背包编号 := uint8(rx.GetInt32())
		背包X := uint8(rx.GetInt32())
		背包Y := uint8(rx.GetInt32())

		if m.V是否死亡 == true {
			break
		}

		物品 := rt.装备_获取指定位置物品(位置)
		if 物品 == nil {
			rt.消息_系统消息(3, "不存在的物品1")
			break
		}
		背包 := rt.背包_获取背包(背包编号)
		if err := rt.背包_查询放置物品(背包, 背包X, 背包Y, 物品); err != nil {
			rt.消息_系统消息(3, err.Error())
			break
		}
		if err := rt.背包_存放物品(背包, 背包X, 背包Y, 物品); err != nil {
			panic("神经的系统")
		}
		rt.装备_卸载指定位置物品(位置)
		rt.同步_角色装备(位置, true)
		rt.同步_背包指定点(背包, 背包X, 背包Y, false)
		rt.角色_属性计算(false)

	case 0x0027: //从背包中取出物品扔到地上
		rx.GetBytes(20)
		背包ID := uint8(rx.GetInt32())
		位置X := uint8(rx.GetInt32())
		位置Y := uint8(rx.GetInt32())
		rx.GetInt32() //0
		if m.V是否死亡 == true {
			break
		}
		背包 := rt.背包_获取背包(背包ID)
		if 物品 := rt.背包_查询位置物品(背包, 位置X, 位置Y); 物品 == nil {
			rt.消息_系统消息(3, "此物品未找到!")
			break
		} else if 物品.V可否交易 == false {
			rt.消息_系统消息(3, "此物品不可丢弃!")
			break
		}
		if 物品, err := rt.背包_取出指定位置物品(背包, 位置X, 位置Y, 0); err != nil {
			rt.消息_系统消息(3, "不存在的物品2!")
			break
		} else {
			rt.同步_背包指定点(背包, 位置X, 位置Y, false)
			m.V空间.F添加内容(E类别_物品, m.X, m.Y, 0, 0, 物品)
		}
	case 0x0028: //在背包中换位置
		rx.GetBytes(20)
		原位置X := uint8(rx.GetInt32())
		原位置Y := uint8(rx.GetInt32())
		新位置X := uint8(rx.GetInt32())
		新位置Y := uint8(rx.GetInt32())

		if m.V是否死亡 == true {
			break
		}
		背包 := &rt.V角色.V背包
		if 双同步, err := rt.背包_物品移动位置(背包, 原位置X, 原位置Y, 背包, 新位置X, 新位置Y); err != nil {
			rt.消息_系统消息(3, err.Error())
			break
		} else {
			if 双同步 == false {
				tx := CreateBuff(18)
				tx.AddInt16(0x0032)
				tx.AddInt32(int32(原位置X))
				tx.AddInt32(int32(原位置Y))
				tx.AddInt32(int32(新位置X))
				tx.AddInt32(int32(新位置Y))
				rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
			} else {
				rt.同步_背包指定点(背包, 原位置X, 原位置Y, true)
				rt.同步_背包指定点(背包, 新位置X, 新位置Y, true)
			}
		}
	case 0x002B: //喝药水 或者执行0~9 F1~F12 上的可以
		rx.GetBytes(20)
		物品外观2D := rx.GetStringAndLen()
		if m.V是否死亡 == true {
			break
		}
		背包 := rt.背包_获取背包(0)
		if 物品信息, err := 物品_获取物品信息_2D(物品外观2D); err == nil {
			x, y, _, ok := rt.背包_查询相同物品位置(背包, 物品信息.Id) //只在个人背包中查询，如果没在
			if ok == false {
				break
			}
			rt.背包_双击背包中的一格(0, x, y)
		} else {
			rt.消息_系统消息(3, "未知物品名称:"+物品外观2D)
		}
		//rt.喝药水(药水名称)
	case 0x0036: //设置传声筒的频道
		rx.GetBytes(20)
		位置 := rx.GetByte()
		频道 := rx.GetStringAndLen()

		if m.V是否死亡 == true {
			break
		}

		if (位置 != 0x0E) && (位置 != 0x0F) {
			panic("不可能在其它位置设置")
		}
		物品ID, ok := rt.V角色.V佩戴物品[位置]
		if ok == false {
			panic("不可能在其它位置设置")
		}
		物品, ok := rt.V物品列表[物品ID]
		if ok == false {
			panic("发现不存在的物品")
		}
		sp := strings.Split(物品.V中文名称, "\n")
		物品.V中文名称 = sp[0] + "\n" + 频道
		物品.Stata.V修改 = true
		物品.Stata.V更新字段["V中文名称"] = true
		rt.装备_卸载指定位置物品(位置)
		rt.同步_角色装备(位置, false)
		rt.装备_穿着指定位置物品(物品, 位置)
		rt.同步_角色装备(位置, true)
	case 0x0037: //通过传声筒说话
		rx.GetBytes(20)
		频道 := rx.GetStringAndLen()
		话语 := rx.GetStringAndLen()

		if m.V是否死亡 == true {
			break
		}
		消息 := &电信{
			来源:   m,
			类型:   E频道,
			频道:   频道,
			通讯内容: 话语,
		}
		m_电信服务 <- 消息
	case 0x003D: //超凯升级属性
		rx.GetBytes(20)
		宝石X := rx.GetInt32()
		宝石Y := rx.GetInt32()
		物品X := rx.GetInt32()
		物品Y := rx.GetInt32()
		t := rx.GetStringAndLen()
		第几个属性, err := strconv.Atoi(t)
		if err != nil {
			rt.消息_系统消息(3, "错误的属性选择")
			break
		}
		背包ID := rx.GetInt32()

		if m.V是否死亡 == true {
			break
		}
		rt.命令行控制(fmt.Sprintf("ItemApplySub %d %d %d %d %d %d", 宝石X, 宝石Y, 物品X, 物品Y, 背包ID, 第几个属性))
	case 0x003F: //打开物品窗口
		rx.GetBytes(20)
	case 0x0045:
		rx.GetBytes(20)
	case 0x0041:
		rx.GetBytes(20)
	case 0x004B: //申请交易
		rx.GetBytes(20)
		交易人 := rx.GetInt32() //交易人

		if m.V是否死亡 == true {
			break
		}
		if _, ok := m.V场景[交易人]; ok == false {
			rt.消息_系统消息(3, "距离过远")
			break
		}
		交易人内容 := m.V空间.F获取内容(交易人)
		if 交易人内容.V是否死亡 == true {
			rt.消息_系统消息(3, "距离过远")
			return
		}
		tx := CreateBuff(6)
		tx.AddInt16(0x0097)
		tx.AddInt32(m.Id)
		F地图_发送信息(交易人内容, &S交换数据{
			V发送人: m,
			V类型:  E交换数据类型_透传数据,
			V内容: S交换角色通讯{
				VCMD:     0x0A,
				VHeadlen: 0,
				V信息:      tx.Buff,
			},
		})
	case 0x004C: //对方同意交易
		rx.GetBytes(20)
		交易人 := rx.GetInt32() //交易人

		if m.V是否死亡 == true {
			break
		}
		交易人内容 := m.F获取身边内容(交易人)
		if 交易人内容 == nil {
			rt.消息_系统消息(3, "距离过远")
			return
		}
		//给自己发
		tx := CreateBuff(6)
		tx.AddInt16(0x0098)
		tx.AddInt32(交易人)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})

		tx = CreateBuff(6)
		tx.AddInt16(0x0098)
		tx.AddInt32(m.Id)
		F地图_发送信息(交易人内容, &S交换数据{
			V发送人: m,
			V类型:  E交换数据类型_透传数据,
			V内容: S交换角色通讯{
				VCMD:     0x0A,
				VHeadlen: 0,
				V信息:      tx.Buff,
			},
		})
	/*case 0x004E: //交易时一方向物品格里放了物品
	rx.GetBytes(20)
	交易人 := rx.GetInt32() //交易人
	rx.GetInt32()        //一直是0
	原X := rx.GetInt32()
	原Y := rx.GetInt32()
	目标X := rx.GetInt32()
	目标Y := rx.GetInt32()
	//给自己发
	tx := CreateBuff(6)
	tx.AddInt16(0x0098)
	tx.AddInt32(交易人)
	rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
	if 内容t, ok := m_all.Load(交易人); ok == true {
		内容 := 内容t.(*StructMap)
		if rt0t, ok := m_RunTime.Load(内容.V内容.(*S角色列表).Id); ok == true {
			tx := CreateBuff(6)
			tx.AddInt16(0x0098)
			tx.AddInt32(m.Id)
			rt0 := rt0t.(*RunTime)
			rt0.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
		}
	}
	*/
	case 0x0051: //交易时一方向物品格里写入了指定金额数字
		rx.GetBytes(20)
		交易人 := rx.GetInt32() //交易人
		交易金额 := rx.GetInt64()

		if m.V是否死亡 == true {
			break
		}
		fmt.Println(交易人, 交易金额)
	case 0x005F: //组队说话
		rx.GetBytes(20)
		rx.GetStringAndLen() //语言
		if m.V是否死亡 == true {
			break
		}
	case 0x0064, 0x0069: //查看行会消息
		rx.GetBytes(20)
		if (rt.V角色.V行会名 == "") || (strings.Index(rt.V角色.V行会名, "+") != -1) {
			rt.动作_显示加入行会()
			break
		}
		rt.动作_显示行会信息()
	case 0x0065: //查看等待添加行会的角色
		rx.GetBytes(20)
		rt.动作_显示申请行会列表()
	case 0x0066: //申请入行会
		rx.GetBytes(20)
		行会名 := rx.GetStringAndLen()
		会长 := &S角色列表{}
		if ok, _ := db.Where("行会名=?", 行会名).Where("会长=?", true).Get(会长); ok == false {
			rt.消息_系统消息(3, "无此行会或此行会已解散!")
			break
		}
		rt.V角色.V行会名 = "+" + 行会名
		db.Update(nil, rt.V角色, []string{})
		rt.消息_系统消息(3, "已申请加入行会:"+行会名)
	case 0x006A: //同意入会
		rx.GetBytes(20)
		角色名 := rx.GetStringAndLen()
		if rt.V角色.V会长 == false {
			rt.消息_系统消息(3, "您无权操作")
			break
		}
		rt.消息_系统消息(3, "同意入会:"+角色名)

	case 0x006B: //不同意入会
		rx.GetBytes(20)
		角色名 := rx.GetStringAndLen()
		if rt.V角色.V会长 == false {
			rt.消息_系统消息(3, "您无权操作")
			break
		}
		rt.消息_系统消息(3, "禁止入会:"+角色名)
	case 0x0082: //打开任务界面
		/*
				0A 14 00 00 68 00 00 00 00 00 00 00 00 00 00 00 62 14
			83 00
			01 00 00 00
			17 00 00 00 5B C8 F8 C2 E5 B4 C4 5D B3 F5 BC B6 20 C8 CE CE F1 20 D6 B8 C1 EE 00
			0B 00 00 00 B1 D8 D0 EB BC FB B6 F7 C4 C8 00
			0F 00 00 00 D2 AA CC FD B6 F7 C4 C8 B5 C4 BD B2 BB B0 00
			00 00 00 00 01 00 00 00 0D 00 00 00 4E 65 77 62 69 65 51 75 65 73 74 32 00 02 00 00 00 00 00 00 00 00 00 00 00
		*/
		/*0A 14 00 00 8C 01 00 00 00 00 00 00 00 00 00 00 86 15
		 83 00
		 02 00 00 00
		//  16 00 00 00 5B C8 F8 C2 E5 B4 C4 5D C2 C3 D0 D0 D5 DF B5 C4 D6 B8 B5 E3 31 00  //左侧标题
		 D6 00 00 00 C6 DB C5 A9 BD CC C4 E3 CE BB D6 C3 D2 C6 B6 AF 7C 7C 3C 54 69 70 3E CE BB D6 C3 D2 C6 B6 AF 7C 31 2E 20 CF EB D2 AA CA D5 B2 D8 B5 C4 B5 D8 B7 BD B0 B4 CF C2 BF EC BD DD BC FC 20 27 52 27 B0 B4 CF C2 B0 B4 C5 A5 7C 32 2E 20 B5 AF B3 F6 BF C9 D2 D4 CA D5 B2 D8 B5 C4 B4 B0 BF DA BA F3 7C 33 2E 20 B0 B4 CF C2 27 B5 C7 C2 BD 27 B0 B4 C5 A5 BA F3 B0 D1 CF D6 D4 DA B5 C4 CE BB D6 C3 CA D5 B2 D8 7C 34 2E 20 D4 DA C8 CE BA CE B5 D8 B7 BD D6 D8 D0 C2 BB D8 B5 BD D4 AD CE BB D6 C3 CA B1 7C 35 2E 20 BF EC BD DD BC FC 20 27 52 27 B0 B4 CF C2 BA F3 D1 A1 D4 F1 D2 D1 CA D5 B2 D8 B5 C4 CE BB D6 C3 7C 36 2E 20 D1 A1 D4 F1 CE BB D6 C3 D2 C6 B6 AF 00
		 0F 00 00 00 B8 FA C6 DB C5 A9 D6 D8 D0 C2 CB B5 BB B0 00
		 17 00 00 00 5B C8 F8 C2 E5 B4 C4 5D B3 F5 BC B6 20 C8 CE CE F1 20 D6 B8 C1 EE 00  //左侧标题
		 0B 00 00 00 B1 D8 D0 EB BC FB B6 F7 C4 C8 00
		 0F 00 00 00 D2 AA CC FD B6 F7 C4 C8 B5 C4 BD B2 BB B0 00
		 00 00 00 00 02 00 00 00 11 00 00 00 4E 51 5F 4E 65 77 62 69 65 41 64 76 69 63 65 31 00
		 02 00 00 00
		 00 00 00 00 0D 00 00 00 4E 65 77 62 69 65 51 75 65 73 74 32 00 02 00 00 00 00 00 00 00 00 00 00 00

		*/
		rx.GetBytes(20)

	case 0x0090: //切换区
		rx.GetBytes(24)
		tx := CreateBuff(6)
		tx.AddInt16(0x00E5)
		tx.AddInt32(rt.V角色.Id)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
		time.Sleep(time.Second * 2)
		m_二次登录[rt.V角色.Id] = 用户.V密码串 //保存密码串
	case 0x00A3: //申请组队
		//
		rt.消息_系统消息(3, "创建新的队伍")
		{
			tx := CreateBuff(2)
			tx.AddInt16(0x00A1)
			rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
		}
		{
			tx := CreateBuff(20)
			tx.AddInt16(0x00A9)
			tx.AddByte(0x00)
			tx.AddStringAndLen("玩家名称")
			rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
		}
		{ //设置队员类型及等级
			tx := CreateBuff(20)
			tx.AddInt16(0x00AD)
			tx.AddStringAndLen("玩家名称")
			tx.AddInt32(100) //等级
			tx.AddInt32(0x00000737)
			tx.AddInt32(0x00000737)
			tx.AddInt32(0x00000002) //职业类型

			rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
		}
		{ //设置队员的位置
			tx := CreateBuff(20)
			tx.AddInt16(0x00AF)
			tx.AddStringAndLen("玩家名称")
			tx.AddByte(0x01)
			tx.AddInt32(0x01)
			tx.AddInt32(0x00) //X
			tx.AddInt32(0x00) //Y
			tx.AddInt32(0x00) //Z
			rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
		}

	case 0x00D4: //NPC购买时，选择某个选项，比如选择道具，药水等
		rx.GetBytes(20)
		NpcId := rx.GetInt32()
		选择标题 := rx.GetStringAndLen()

		if m.V是否死亡 == true {
			break
		}
		if rt.V角色.V状态 != E角色状态_NPC {
			panic("没有询问NPC就能选择菜单?")
		}
		rt.NPC_选择菜单(NpcId, 选择标题)
	case 0x00D5: //用户在购买物品时，点击了"出售"
		rx.GetBytes(20)
		rx.GetInt32() //NPCid
		if rt.V角色.V状态 != E角色状态_NPC {
			panic("疑似外挂")
		}
	case 0x00D6: //用户在购买物品时，点击了"维修"
		rx.GetBytes(20)
		rx.GetInt32() //NPCid
		if rt.V角色.V状态 != E角色状态_NPC {
			panic("疑似外挂2")
		}
	case 0x00D7: //用户购买指定物品
		rx.GetBytes(20)
		npcid := rx.GetInt32() //NPCid
		物品ID := rx.GetInt32()
		数量 := uint16(rx.GetInt32())

		if m.V是否死亡 == true {
			break
		}
		if rt.V角色.V状态 != E角色状态_NPC {
			panic("疑似外挂3")
		}
		rt.NPC_购买物品(npcid, 物品ID, 数量)
	case 0x00D8: //出售物品
		rx.GetBytes(20)
		npcid := rx.GetInt32()       //NPCid
		背包ID := uint8(rx.GetInt32()) //可能是背包编号 00000000
		x := uint8(rx.GetInt32())    //坐标X
		y := uint8(rx.GetInt32())    //坐标Y

		if m.V是否死亡 == true {
			break
		}
		if rt.V角色.V状态 != E角色状态_NPC {
			panic("疑似外挂4")
		}

		if _, ok := m.V场景[npcid]; ok == false {
			rt.消息_系统消息(3, "距离过远")
			return
		}
		背包 := rt.背包_获取背包(背包ID)
		物品, err := rt.背包_取出指定位置物品(背包, x, y, 0)
		if err != nil {
			rt.消息_系统消息(3, err.Error())
			return
		}
		db.Where("id=?", 物品.Id).Delete(物品)
		价格 := 售价(物品.V售价)
		if 价格 > 0 {
			rt.V角色.V金币 += int64(价格)
			rt.发送用户信息(用户信息_金币)
		}
		rt.同步_背包指定点(背包, x, y, false)
	//case 0x00F0: //关闭当前打开的仓库

	case 0x00F3: //创建一个个人仓库
		rx.GetBytes(20)
		仓库名称 := rx.GetStringAndLen()
		if m.V是否死亡 == true {
			break
		}
		if rt.V角色.V状态 != E角色状态_仓库 {
			panic("疑似外挂-背包")
		}
		状态 := rt.V角色.V状态内容.(*S状态_仓库)
		if 状态.个人仓库 == true {
			仓库 := &S背包列表{}
			if ok, _ := db.Where("类型=4").Where("uid=?", rt.V角色.Id).Where("主类=?", 状态.主类).Where("name=?", 仓库名称).Get(仓库); ok == true {
				rt.消息_系统消息(3, "此名称不可用")
				break
			}
			仓库.Uid = rt.V角色.Id
			仓库.Time = time.Now().Add(time.Hour * 24 * 365 * 10) //30年使用期
			仓库.V主类 = 状态.主类
			仓库.Name = 仓库名称
			仓库.V类型 = 4
			if _, err := db.Insert(仓库); err != nil {
				rt.消息_系统消息(3, "无法创建仓库:"+err.Error())
				break
			}
		} else {
			if rt.V角色.V行会名 == "" || strings.Index(rt.V角色.V行会名, "+") != -1 {
				rt.消息_系统消息(3, "您未加入行会")
				break
			}
			if rt.V角色.V会长 == false {
				rt.消息_系统消息(3, "您不是行会会长")
				break
			}
			仓库 := &S背包列表{}
			if ok, _ := db.Where("类型=5").Where("uid=?", rt.V角色.Id).Where("主类=?", 状态.主类).Where("name=?", 仓库名称).Where("行会名=?", rt.V角色.V行会名).Get(仓库); ok == false {
				rt.消息_系统消息(3, "此名称不可用")
				break
			}

			仓库.Uid = rt.V角色.Id
			仓库.Time = time.Now().Add(time.Hour * 24 * 365 * 10) //30年使用期
			仓库.V主类 = 状态.主类
			仓库.V类型 = 5
			仓库.Name = 仓库名称
			仓库.V行会名 = rt.V角色.V行会名
			if _, err := db.Insert(仓库); err != nil {
				rt.消息_系统消息(3, "无法创建仓库:"+err.Error())
				break
			}
		}
	case 0x00F4: //打开背包
		rx.GetBytes(20)
		仓库ID := rx.GetInt32()
		if m.V是否死亡 == true {
			break
		}
		仓库 := &S背包列表{Id: 仓库ID}
		if ok, _ := db.Get(仓库); ok == false {
			rt.消息_系统消息(3, "无法获取仓库")
			break
		}
		rt.背包_同步到变量(仓库)
		rt.背包_发送仓库物品列表(仓库)

	case 0x00FA: //从背包中移动到仓库中
		rx.GetBytes(20)
		仓库ID := rx.GetInt32()
		背包ID := uint8(rx.GetInt32())
		原位置X := uint8(rx.GetInt32())
		原位置Y := uint8(rx.GetInt32())
		新位置X := uint8(rx.GetInt32())
		新位置Y := uint8(rx.GetInt32())
		背包 := rt.背包_获取背包(背包ID)

		仓库 := &S背包列表{Id: 仓库ID}
		if ok, _ := db.Get(仓库); ok == false {
			rt.消息_系统消息(3, "无法获取仓库")
			break
		}
		rt.背包_同步到变量(仓库)
		_, err := rt.背包_物品移动位置(背包, 原位置X, 原位置Y, 仓库, 新位置X, 新位置Y)
		if err != nil {
			rt.消息_系统消息(3, err.Error())
			break
		}
		//物品 := rt.背包_查询位置物品(仓库, 新位置X, 新位置Y)
		rt.背包_同步到数据库(仓库)
		rt.同步_背包指定点(背包, 原位置X, 原位置Y, false)
		rt.同步_背包指定点(仓库, 新位置X, 新位置Y, false)
	case 0X00FC: //从仓库中移到背包中
		rx.GetBytes(20)
		仓库ID := rx.GetInt32()
		原位置X := uint8(rx.GetInt32())
		原位置Y := uint8(rx.GetInt32())
		新位置X := uint8(rx.GetInt32())
		新位置Y := uint8(rx.GetInt32())
		背包ID := uint8(rx.GetInt32())
		背包 := rt.背包_获取背包(背包ID)

		仓库 := &S背包列表{Id: 仓库ID}
		if ok, _ := db.Get(仓库); ok == false {
			rt.消息_系统消息(3, "无法获取仓库.")
			break
		}
		rt.背包_同步到变量(仓库)
		_, err := rt.背包_物品移动位置(仓库, 原位置X, 原位置Y, 背包, 新位置X, 新位置Y)
		if err != nil {
			rt.消息_系统消息(3, err.Error())
			break
		}
		rt.背包_同步到数据库(仓库)
		rt.同步_背包指定点(仓库, 原位置X, 原位置Y, false)
		rt.同步_背包指定点(背包, 新位置X, 新位置Y, false)
	case 0X00FE: //在仓库中移动物品
		rx.GetBytes(20)
		仓库ID := rx.GetInt32()
		原位置X := uint8(rx.GetInt32())
		原位置Y := uint8(rx.GetInt32())
		新位置X := uint8(rx.GetInt32())
		新位置Y := uint8(rx.GetInt32())

		仓库 := &S背包列表{Id: 仓库ID}
		if ok, _ := db.Get(仓库); ok == false {
			rt.消息_系统消息(3, "无法获取仓库")
			break
		}
		rt.背包_同步到变量(仓库)
		if 合并, err := rt.背包_物品移动位置(仓库, 原位置X, 原位置Y, 仓库, 新位置X, 新位置Y); err != nil {
			rt.消息_系统消息(3, err.Error())
			break
		} else {
			if 合并 == true {

			} else {

			}
			rt.背包_同步到数据库(仓库)
		}
		rt.同步_背包指定点(仓库, 原位置X, 原位置Y, false)
		rt.同步_背包指定点(仓库, 新位置X, 新位置Y, false)

	case 0x0105: //与NPC对话时选择选项
		rx.GetBytes(20)
		npcid := rx.GetInt32()
		关键字 := rx.GetStringAndLen() //关键字

		if m.V是否死亡 == true {
			break
		}
		rt.Func发起对话NPC(npcid, 关键字)
	case 0x0124: //语言控制
		rx.GetBytes(19)
		rx.GetByte()
		话语 := rx.GetStringAndLen()

		if m.V是否死亡 == true {
			break
		}

		rt.命令行控制(话语)
	case 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012D, 0x0136, 0x0137, 0x013F, 0x013D, 0x0164, 0x0166:
		var 步骤 uint8
		var 技能英文名 string
		var 攻击序号, 目标ID, 坐标X, 坐标Y, 坐标Z int32
		var 目标 *StructMap
		rx.GetBytes(20)

		switch cmd {
		case 0x0127:
			技能英文名 = rx.GetStringAndLen() //技能名称
			攻击序号 = rx.GetInt32()         //好像是序号
			目标ID = rx.GetInt32()         //怪物ID
			坐标X = rx.GetInt32()          //坐标X :=
			坐标Y = rx.GetInt32()          //坐标Y :=
			坐标Z = rx.GetInt32()          //坐标Z :=
			rx.GetFloat()                //方向？
			rx.GetInt32()
			rx.GetInt32()
			步骤 = 1
		case 0x0128:
			技能英文名 = rx.GetStringAndLen() //技能名称 :=
			攻击序号 = rx.GetInt32()         //好像是序号
			目标ID = rx.GetInt32()
			坐标X = rx.GetInt32() //坐标X :=
			坐标Y = rx.GetInt32() //坐标Y :=
			坐标Z = rx.GetInt32() //		坐标Z :=
			rx.GetFloat()
			rx.GetInt32()
			步骤 = 1
		case 0x0129: //Fun处理物理攻击(rx)
			攻击序号 = rx.GetInt32() //攻击的编号
			rx.GetInt32()        //用户位置
			rx.GetInt32()        //用户位置
			目标ID = rx.GetInt32() //用户位置
			坐标X = rx.GetInt32()  //坐标X :=
			坐标Y = rx.GetInt32()  //坐标Y :=
			坐标Z = rx.GetInt32()  //		坐标Z :=
			rx.GetInt32()
			步骤 = 2
			技能英文名 = rt.V角色.V物理攻击技能栏
		case 0x012A: //魔法攻击动作
			技能英文名 = rx.GetStringAndLen() //技能名称
			攻击序号 = rx.GetInt32()         //好像是序号
			目标ID = rx.GetInt32()
			坐标X = rx.GetInt32() //坐标X
			坐标Y = rx.GetInt32() //坐标Y
			坐标Z = rx.GetInt32() //坐标Z
			rx.GetFloat()       //t :=
			rx.GetInt32()
			步骤 = 1
		case 0x012B: //角色向指定位置的怪发动攻击的动作
			攻击序号 = rx.GetInt32() //未知
			目标ID = rx.GetInt32() //怪物ID
			坐标X = rx.GetInt32()  //坐标X
			坐标Y = rx.GetInt32()  //坐标Y
			坐标Z = rx.GetInt32()  //坐标Z
			步骤 = 2
			技能英文名 = rt.V角色.V魔法攻击技能栏
		case 0x012D: //魔法攻击 已经攻击到怪物 ，这个在后期需要做下处理，没有前面的攻击动作，这个动作不成立
			攻击序号 = rx.GetInt32() //序号
			坐标X = rx.GetInt32()  //
			坐标Y = rx.GetInt32()  //
			目标ID = rx.GetInt32()
			rx.GetInt32()
			rx.GetInt32()
			坐标Z = rx.GetInt32()
			步骤 = 3
			技能英文名 = rt.V角色.V魔法攻击技能栏
		case 0x0137: //弓手攻击到位
			攻击序号 = rx.GetInt32() //序号
			坐标X = rx.GetInt32()  //
			坐标Y = rx.GetInt32()  //
			目标ID = rx.GetInt32()
			rx.GetInt32()
			rx.GetInt32()
			坐标Z = rx.GetInt32()
			rx.GetInt32()
			步骤 = 1
			技能英文名 = rt.V角色.V物理攻击技能栏
		case 0x0136: //弓手攻击动作  //这个数据包需要测试
			技能英文名 = rx.GetStringAndLen() //技能名称
			攻击序号 = rx.GetInt32()         //好像是序号
			坐标X = rx.GetInt32()          //怪物ID
			坐标Y = rx.GetInt32()
			坐标Z = rx.GetInt32()
			目标ID = rx.GetInt32()
			rx.GetFloat()
			rx.GetInt32()
			rx.GetInt32()
			rx.GetInt32()
			步骤 = 1
		case 0x013D: //弓手使用辅助技能 步骤2
			技能英文名 = rx.GetStringAndLen()
			rx.GetByte() //01
			坐标X = m.X
			坐标Y = m.Y
			坐标Z = m.Z
			目标ID = m.Id //设置目标为自己
			步骤 = 2
		case 0x013F: //弓手使用辅助技能 步骤1
			技能英文名 = rx.GetStringAndLen()
			坐标X = m.X
			坐标Y = m.Y
			坐标Z = m.Z
			目标 = m //设置目标为自己
			步骤 = 1
		case 0x0164: //使用高阶技能进行攻击
			技能英文名 = rx.GetStringAndLen()
			目标ID = rx.GetInt32()
			坐标X = rx.GetInt32()
			坐标Y = rx.GetInt32()
			坐标Z = rx.GetInt32()
			步骤 = 1
			攻击序号 = 0
		case 0x0166: //使用高阶技能进行攻击
			技能英文名 = rx.GetStringAndLen()
			目标ID = rx.GetInt32()
			坐标X = rx.GetInt32() //X
			坐标Y = rx.GetInt32() //Y
			坐标Z = int32(0)
			步骤 = 2
			攻击序号 = 0
		}
		技能信息, err := 技能_获取技能信息_英文(技能英文名, rt.V角色.V职业)
		if err != nil {
			rt.消息_系统消息(3, "错误,技能名称:"+技能英文名+"详细信息:"+err.Error())
			break
		}
		if 技能信息.V辅助自己 == true {
			目标 = m
		} else if 目标ID == m.Id {
			目标 = m
		}
		if 目标 == nil {
			目标 = m.F获取身边内容(目标ID)
		}
		/*if 目标 == nil {
			rt.消息_系统消息(3, "目标距离过远")
			break
		}*/
		rt.攻击_处理使用技能(步骤, 技能信息, 目标, 攻击序号, 坐标X, 坐标Y, 坐标Z)
	case 0x0139: //$表情动作
		rx.GetBytes(20)
		rx.GetStringAndLen()
		rx.GetFloat()
	case 0x016A: //要求显示宠物
		rx.GetBytes(20)
		//rt.动作_显示宠物()

	case 0x0190: //摆摊
		rx.GetBytes(20)

		if m.V是否死亡 == true {
			break
		}
		tx := CreateBuff(50)
		tx.AddInt32(m.Id)
		tx.AddInt16(0x0193)
		tx.AddStringAndLen(rt.V角色.V名字 + " 的地摊")
		tx.AddByte(0x00)
		tx.AddByte(0X01)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff[4:]})
		向周边发送消息(m, 0x0B, 4, tx.Buff)
		rt.V角色.V状态 = E角色状态_摆摊_准备中
		rt.V角色.V状态内容 = &S摆摊列表{}
	case 0x0194: //确认摆摊
		rx.GetBytes(20)
		rx.GetByte()
		摆摊名称 := rx.GetStringAndLen()
		rx.GetStringAndLen()
		rx.GetByte() //1

		if m.V是否死亡 == true {
			break
		}
		if rt.V角色.V状态 != E角色状态_摆摊_准备中 {
			panic("没有准备，如何开始？")
		}
		rt.V角色.V状态 = E角色状态_摆摊
		tx := CreateBuff(100)
		tx.AddInt32(m.Id)
		tx.AddInt16(0x0195)
		tx.AddByte(0x01)
		tx.AddStringAndLen(摆摊名称)
		tx.AddByte(0x00)
		tx.AddStringAndLen("")
		tx.AddByte(0x01)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff[4:]})
		向周边发送消息(m, 0x0B, 4, tx.Buff)
	case 0x0196: //取消摆摊
		rx.GetBytes(20)

		if m.V是否死亡 == true {
			break
		}

		tx := CreateBuff(6)
		tx.AddInt32(m.Id)
		tx.AddInt16(0x0197)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff[4:]})
		向周边发送消息(m, 0x0B, 4, tx.Buff)
		rt.V角色.V状态 = E角色状态_正常
		rt.V角色.V状态内容 = nil //清空表

	case 0x0198: //在摆摊前放置物品
		rx.GetBytes(20)
		背包ID := uint8(rx.GetInt32())
		原X := uint8(rx.GetInt32())
		原Y := uint8(rx.GetInt32())
		目标X := uint8(rx.GetInt32())
		目标Y := uint8(rx.GetInt32())
		复数 := rx.GetBool()
		金币 := rx.GetInt64() //价格 :=

		if m.V是否死亡 == true {
			break
		}
		摆摊 := rt.V角色.V状态内容.(*S摆摊列表)
		tx := CreateBuff(100)
		tx.AddInt16(0x0199)
		tx.AddInt32(int32(背包ID))
		tx.AddInt32(int32(原X))
		tx.AddInt32(int32(原Y))
		tx.AddInt32(int32(目标X))
		tx.AddInt32(int32(目标Y))
		背包 := rt.背包_获取背包(背包ID)
		物品 := rt.背包_查询位置物品(背包, 原X, 原Y)
		rt.物品_物品信息(tx, 物品)
		tx.AddBool(复数)
		tx.AddInt64(金币)
		rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})

		摆件 := &S摆摊物品{V背包ID: 背包ID, V背包X: 原X, V背包Y: 原Y, V摊位X: 目标X, V摊位Y: 目标Y, V物品: 物品, V售价: 金币}
		摆摊.V物品列表 = append(摆摊.V物品列表, 摆件)
	case 0x019C: //摆摊时，取回一个物品
		rx.GetBytes(20)
		摆摊X := uint8(rx.GetInt32())
		摆摊Y := uint8(rx.GetInt32())

		if m.V是否死亡 == true {
			break
		}
		摆摊 := rt.V角色.V状态内容.(*S摆摊列表)
		var 摆摊物品 *S摆摊物品
		for i, v := range 摆摊.V物品列表 {
			if (v.V摊位X == 摆摊X) && (v.V摊位Y == 摆摊Y) {
				摆摊物品 = v
				old := 摆摊.V物品列表
				摆摊.V物品列表 = 摆摊.V物品列表[:i]
				for ii := i + 1; ii < len(old); ii++ {
					摆摊.V物品列表 = append(摆摊.V物品列表, old[ii])
				}
				break
			}
		}
		if 摆摊 == nil {
			rt.消息_系统消息(3, "错误的位置")
		} else {
			rt.动作_摆摊取回物品(摆摊物品.V背包ID, 摆摊物品.V背包X, 摆摊物品.V背包Y, 摆摊物品.V摊位X, 摆摊物品.V摊位Y)
		}
	case 0x019F: //查看摊位
		rx.GetBytes(20)
		交易人 := rx.GetInt32() //

		if m.V是否死亡 == true {
			break
		}
		交易人内容 := m.F获取身边内容(交易人)
		if 交易人内容 == nil {
			rt.消息_系统消息(3, "距离过远")
			break
		}
		F地图_发送信息(交易人内容, &S交换数据{
			V发送人: m,
			V类型:  E交换数据类型_查看摊位,
		})

	case 0x01A1: //购买摆摊物品
		rx.GetBytes(20)
		背包ID := uint8(rx.GetInt32()) //0
		角色ID := rx.GetInt32()
		摊位X := uint8(rx.GetInt32())
		摊位Y := uint8(rx.GetInt32())
		rx.GetBool()                 //数量
		rx.GetInt32()                //原数量 :=
		买几个 := uint16(rx.GetInt32()) //0
		购买金额 := rx.GetInt64()        //价格 :=

		if m.V是否死亡 == true {
			break
		}
		rt.摆摊_购买指定物品(背包ID, 角色ID, 摊位X, 摊位Y, 买几个, 购买金额)
	//3: 自己背包中添加物品
	case 0x01A5: //消失摆摊
		rx.GetBytes(20)
		交易人 := rx.GetInt32() //

		if m.V是否死亡 == true {
			break
		}
		交易人内容 := m.F获取身边内容(交易人)
		if 交易人内容 == nil {
			rt.消息_系统消息(3, "距离过远")
			break
		}
		F地图_发送信息(交易人内容, &S交换数据{
			V类型:  E交换数据类型_取消查看摊位,
			V发送人: m,
		})
	case 0x01A9: //在角色区等待,已经登录了,不用关心了
		rx.GetBytes(20)
	case 0x01AB: //选择称号
		rx.GetBytes(20)
		rx.GetStringAndLen()
	case 0x01B2: //从红背包移动到红背包中 ID需要+1
		rx.GetBytes(20)
		背包ID := uint8(rx.GetInt32() + 1)
		原位置X := uint8(rx.GetInt32())
		原位置Y := uint8(rx.GetInt32())
		新位置X := uint8(rx.GetInt32())
		新位置Y := uint8(rx.GetInt32())

		if m.V是否死亡 == true {
			break
		}
		背包 := rt.背包_获取背包(背包ID)
		if 双同步, err := rt.背包_物品移动位置(背包, 原位置X, 原位置Y, 背包, 新位置X, 新位置Y); err != nil {
			rt.消息_系统消息(3, err.Error())
			break
		} else {
			if 双同步 == false {
				tx := CreateBuff(22)
				tx.AddInt16(0x01B5)
				tx.AddInt32(int32(背包ID - 1))
				tx.AddInt32(int32(原位置X))
				tx.AddInt32(int32(原位置Y))
				tx.AddInt32(int32(新位置X))
				tx.AddInt32(int32(新位置Y))
				rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
			} else {
				rt.同步_背包指定点(背包, 原位置X, 原位置Y, true)
				rt.同步_背包指定点(背包, 新位置X, 新位置Y, true)
			}
		}

	case 0x01B8: //从背包移动红背包中 这里的ID就是背包ID，不用加1
		rx.GetBytes(20)
		原背包ID := uint8(rx.GetInt32())
		原位置X := uint8(rx.GetInt32())
		原位置Y := uint8(rx.GetInt32())
		目标背包ID := uint8(rx.GetInt32())
		新位置X := uint8(rx.GetInt32())
		新位置Y := uint8(rx.GetInt32())

		if m.V是否死亡 == true {
			break
		}
		原背包 := rt.背包_获取背包(原背包ID)
		目标背包 := rt.背包_获取背包(目标背包ID)
		if _, err := rt.背包_物品移动位置(原背包, 原位置X, 原位置Y, 目标背包, 新位置X, 新位置Y); err != nil {
			rt.消息_系统消息(3, err.Error())
			break
		}
		rt.同步_背包指定点(原背包, 原位置X, 原位置Y, true)
		rt.同步_背包指定点(目标背包, 新位置X, 新位置Y, true)

	case 0x01BB: //打开红背包，蓝黄背包
		rx.GetBytes(20)
		背包ID := uint8(rx.GetInt32() + 1)

		if m.V是否死亡 == true {
			break
		}
		背包 := rt.背包_获取背包(背包ID)
		rt.背包_输出附助背包信息(背包)
	//case 0x03F6: //从背包中取出一件物品，仍到地上
	/*0C 14 0E 00 37 00 00 00 00 00 00 00 00 00 00 00 35 14
	F6 03 3D 66 FB FF FF BA 0C 00 00 00 00 00 01 00
	E1 E9 FF FF A6 09 3C 00 00 00 00 00 32 7D 00 00 00 00 00 00 50 37 1A 10 FF FF FF FF 04 F9 18 00 52 66 FB FF 5E BB 0C 00 D7 E9 FF FF 00 CB 75 07 44 00 00 80 3F
	*/
	/*rx.GetBytes(20)
	rx.GetInt32() //坐标X
	rx.GetInt32() //坐标Y
	rx.GetInt32() //坐标Z
	rx.GetInt16()
	*/
	default:
		fmt.Printf("未知[%04d]:%s\r\n", len(rx.Buff), Byte2String(rx.Buff))
		rt.消息_系统消息(3, "未知指令:"+Byte2String(rx.GetBytes(len(rx.Buff))))
	}
}

//设置游戏里的时间
func 系统_游戏时间服务() {
	m_RunTime.Range(func(key, value interface{}) bool {
		//24字节，最后四位是时间
		value.(*RunTime).AddHeadSend10(0x0A, [][]byte{{}, String2Byte("BB0000000000")})
		return true
	})
}
